﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.Identity;

namespace EmptoolWebApp.Models
{
    public class AzureStorageIdentityUser : EmptoolWebApp.Entities.UserAccountEntity, Microsoft.AspNet.Identity.IUser
    {
        public string Id
        {
            get
            {
                return this.PartitionKey;
            }
        }

        private string _userName = string.Empty;
        public string UserName
        {
            get
            {
                return this._userName;
            }

            set
            {
                this._userName = value;
            }
        }

        public async Task<System.Security.Claims.ClaimsIdentity> GenerateUserIdentityAsync(
            Microsoft.AspNet.Identity.UserManager<AzureStorageIdentityUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);

            // TODO: Add custom user claims here
            userIdentity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Email, this.Email));

            return userIdentity;
        }

    }

    public class AzureStorageUserStore : 
        Microsoft.AspNet.Identity.IUserStore<AzureStorageIdentityUser>, 
        Microsoft.AspNet.Identity.IUserPasswordStore<AzureStorageIdentityUser>,
        Microsoft.AspNet.Identity.IUserEmailStore<AzureStorageIdentityUser>,
        Microsoft.AspNet.Identity.IUserLockoutStore<AzureStorageIdentityUser, string>,
        Microsoft.AspNet.Identity.IUserTwoFactorStore<AzureStorageIdentityUser, string>,
        Microsoft.AspNet.Identity.IUserLoginStore<AzureStorageIdentityUser>,
        Microsoft.AspNet.Identity.IUserPhoneNumberStore<AzureStorageIdentityUser>
    {
        public Task AddLoginAsync(AzureStorageIdentityUser user, UserLoginInfo login)
        {
            throw new NotImplementedException();
        }

        public Task CreateAsync(AzureStorageIdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            if (string.IsNullOrWhiteSpace(user.PartitionKey))
            {
                user.PartitionKey = user.Email.ToLowerInvariant();
            }

            if (user.RowKey == null)
            {
                user.RowKey = string.Empty;
            }

            try
            {
                // Step-by-step syntax
                //Microsoft.WindowsAzure.Storage.Table.TableOperation insertOperation = Microsoft.WindowsAzure.Storage.Table.TableOperation.Insert(user);
                //Microsoft.WindowsAzure.Storage.Table.CloudTable tbl = Helpers.AzureStorageHelper.GetStorageTable(Entities.UserAccountEntity.TABLE_NAME);
                //tbl.Execute(insertOperation);

                // Fluent syntax
                Helpers.AzureStorageHelper.GetStorageTable(Entities.UserAccountEntity.TABLE_NAME).Execute(
                    Microsoft.WindowsAzure.Storage.Table.TableOperation.Insert(user));
            }
            catch (Exception)
            {
                throw;
            }

            return Task.FromResult<object>(null);
        }

        public Task DeleteAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
        }

        public Task<AzureStorageIdentityUser> FindAsync(UserLoginInfo login)
        {
            throw new NotImplementedException();
        }

        public Task<AzureStorageIdentityUser> FindByEmailAsync(string email)
        {
            AzureStorageIdentityUser result = null;

            Microsoft.WindowsAzure.Storage.Table.CloudTable tbl = 
                Helpers.AzureStorageHelper.GetStorageTable(Entities.UserAccountEntity.TABLE_NAME);

            Microsoft.WindowsAzure.Storage.Table.TableOperation retrieveOperation =
                Microsoft.WindowsAzure.Storage.Table.TableOperation.Retrieve<AzureStorageIdentityUser>(email.ToLowerInvariant(), string.Empty);

            Microsoft.WindowsAzure.Storage.Table.TableResult tableResult = tbl.Execute(retrieveOperation);

            result = tableResult.Result as AzureStorageIdentityUser;

            return Task.FromResult<AzureStorageIdentityUser>(result);
        }

        public Task<AzureStorageIdentityUser> FindByIdAsync(string userId)
        {
            AzureStorageIdentityUser result = null;

            if (string.IsNullOrWhiteSpace(userId))
            {
                return Task.FromResult<AzureStorageIdentityUser>(result);
            }

            Microsoft.WindowsAzure.Storage.Table.CloudTable tbl =
                Helpers.AzureStorageHelper.GetStorageTable(Entities.UserAccountEntity.TABLE_NAME);

            Microsoft.WindowsAzure.Storage.Table.TableOperation retrieveOperation =
                Microsoft.WindowsAzure.Storage.Table.TableOperation.Retrieve<AzureStorageIdentityUser>(userId.ToLowerInvariant(), string.Empty);

            Microsoft.WindowsAzure.Storage.Table.TableResult tableResult = tbl.Execute(retrieveOperation);

            result = tableResult.Result as AzureStorageIdentityUser;

            return Task.FromResult<AzureStorageIdentityUser>(result);
        }

        public Task<AzureStorageIdentityUser> FindByNameAsync(string userName)
        {
            AzureStorageIdentityUser result = null;

            if (string.IsNullOrWhiteSpace(userName))
            {
                return Task.FromResult<AzureStorageIdentityUser>(result);
            }

            Microsoft.WindowsAzure.Storage.Table.CloudTable tbl =
                Helpers.AzureStorageHelper.GetStorageTable(Entities.UserAccountEntity.TABLE_NAME);

            Microsoft.WindowsAzure.Storage.Table.TableOperation retrieveOperation =
                Microsoft.WindowsAzure.Storage.Table.TableOperation.Retrieve<AzureStorageIdentityUser>(userName.ToLowerInvariant(), string.Empty);

            Microsoft.WindowsAzure.Storage.Table.TableResult tableResult = tbl.Execute(retrieveOperation);

            result = tableResult.Result as AzureStorageIdentityUser;

            return Task.FromResult<AzureStorageIdentityUser>(result);
        }

        public Task<int> GetAccessFailedCountAsync(AzureStorageIdentityUser user)
        {
            // TODO: 
            // throw new NotImplementedException();
            int result = 0;

            return Task.FromResult<int>(result);
        }

        public Task<string> GetEmailAsync(AzureStorageIdentityUser user)
        {
            string result = string.Empty;

            result = user.Email;

            return Task.FromResult<string>(result);
        }

        public Task<bool> GetEmailConfirmedAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task<bool> GetLockoutEnabledAsync(AzureStorageIdentityUser user)
        {
            bool result = true;

            return Task.FromResult<bool>(result);
        }

        public Task<DateTimeOffset> GetLockoutEndDateAsync(AzureStorageIdentityUser user)
        {
            DateTimeOffset lockoutEndDateOffset = new DateTimeOffset(DateTime.UtcNow.AddDays(-1));

            return Task.FromResult<DateTimeOffset>(lockoutEndDateOffset);
        }

        public Task<IList<UserLoginInfo>> GetLoginsAsync(AzureStorageIdentityUser user)
        {
            return Task.FromResult<IList<UserLoginInfo>>(new List<UserLoginInfo>());
            //throw new NotImplementedException();
        }

        public Task<string> GetPasswordHashAsync(AzureStorageIdentityUser user)
        {
            string passwordHash = user.PasswordHash;

            return Task.FromResult<string>(passwordHash);
        }

        public Task<string> GetPhoneNumberAsync(AzureStorageIdentityUser user)
        {
            string result = string.Empty;

            result = user.PhoneNumber;

            return Task.FromResult<string>(result);
        }

        public Task<bool> GetPhoneNumberConfirmedAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task<bool> GetTwoFactorEnabledAsync(AzureStorageIdentityUser user)
        {
            bool result = false;

            // Disable 2FA authentication

            //throw new NotImplementedException();
            return Task.FromResult<bool>(result);
        }

        public Task<bool> HasPasswordAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task<int> IncrementAccessFailedCountAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task RemoveLoginAsync(AzureStorageIdentityUser user, UserLoginInfo login)
        {
            throw new NotImplementedException();
        }

        public Task ResetAccessFailedCountAsync(AzureStorageIdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task SetEmailAsync(AzureStorageIdentityUser user, string email)
        {
            throw new NotImplementedException();
        }

        public Task SetEmailConfirmedAsync(AzureStorageIdentityUser user, bool confirmed)
        {
            throw new NotImplementedException();
        }

        public Task SetLockoutEnabledAsync(AzureStorageIdentityUser user, bool enabled)
        {
            // Do not have the concept of lockout; ignore for now
            return Task.FromResult<object>(null);
        }

        public Task SetLockoutEndDateAsync(AzureStorageIdentityUser user, DateTimeOffset lockoutEnd)
        {
            throw new NotImplementedException();
        }

        public Task SetPasswordHashAsync(AzureStorageIdentityUser user, string passwordHash)
        {
            //Guid saltGuid = Guid.NewGuid();
            //user.PasswordSalt = saltGuid.ToString();
            //byte[] saltBytes = saltGuid.ToByteArray();
            //byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(passwordHash);
            //byte[] hashBytes = EmptoolWebApp.Helpers.CryptographyHelper.GetSHA256Hash(passwordBytes, saltBytes);
            //user.PasswordHash = Convert.ToBase64String(hashBytes);

            user.PasswordHash = passwordHash; // Using the default password hashing algorithm inherited from UserManager

            return Task.FromResult<object>(null);
        }

        public Task SetPhoneNumberAsync(AzureStorageIdentityUser user, string phoneNumber)
        {
            throw new NotImplementedException();
        }

        public Task SetPhoneNumberConfirmedAsync(AzureStorageIdentityUser user, bool confirmed)
        {
            throw new NotImplementedException();
        }

        public Task SetTwoFactorEnabledAsync(AzureStorageIdentityUser user, bool enabled)
        {
            throw new NotImplementedException();
        }

        public Task UpdateAsync(AzureStorageIdentityUser user)
        {
            try
            {
                Microsoft.WindowsAzure.Storage.Table.CloudTable tbl =
                Helpers.AzureStorageHelper.GetStorageTable(EmptoolWebApp.Entities.UserAccountEntity.TABLE_NAME);
                Microsoft.WindowsAzure.Storage.Table.TableOperation updateOperation =
                        Microsoft.WindowsAzure.Storage.Table.TableOperation.Replace(user);
                tbl.Execute(updateOperation);
            }
            catch (Exception)
            {

                throw;
            }

            return Task.FromResult<object>(null);
        }
    }

    public class AzureStorageIdentityRole : Microsoft.AspNet.Identity.IRole
    {
        private string _id = string.Empty;
        public string Id
        {
            get
            {
                return this._id;
            }
        }

        private string _name = string.Empty;
        public string Name
        {
            get
            {
                return this._name;
            }

            set
            {
                this._name = value;
            }
        }
    }

    public class AzureStorageRoleStore : Microsoft.AspNet.Identity.IRoleStore<AzureStorageIdentityRole>
    {
        public Task CreateAsync(AzureStorageIdentityRole role)
        {
            throw new NotImplementedException();
        }

        public Task DeleteAsync(AzureStorageIdentityRole role)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public Task<AzureStorageIdentityRole> FindByIdAsync(string roleId)
        {
            throw new NotImplementedException();
        }

        public Task<AzureStorageIdentityRole> FindByNameAsync(string roleName)
        {
            throw new NotImplementedException();
        }

        public Task UpdateAsync(AzureStorageIdentityRole role)
        {
            throw new NotImplementedException();
        }
    }
}